﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SlimDX.Direct3D9;
using System.Windows;
using System.Windows.Media;
using System.Diagnostics;

namespace Microsoft.Research.DynamicDataDisplay.DirectX2D
{
    public abstract class DirectXChart : ViewportElement2D, IRenderEngine, IDisposable
	{
        //private DirectXHost _dxHost;

        //protected DirectXHost DxHost
        //{
        //    get { return _dxHost; }
        //}

        private SlimDXControl _slimDXControl;

        public SlimDXControl SlimDXControl
        {
            get { return _slimDXControl; }
        }

       //-------------------

        new protected Plotter2D Plotter2D
        {
            get { return (Plotter2D)this.plotter; }
        }

        
        
        new protected Viewport2D Viewport
        {
            get
            {
                return Plotter2D.Viewport;
            }
        }

        //----------

		protected Device Device
		{
            //get { return _dxHost != null ? _dxHost.Device : null; }
            get { return _slimDXControl != null ? _slimDXControl.Device : null; }
		}

		protected Direct3D Direct3D
		{
            //get { return _dxHost.Direct3D; }
            get { return _slimDXControl.Direct3D; }
		}

        public bool ShowFrameRate { get; set; }

        #region Private Fields
        private Stopwatch _stopwatch = new Stopwatch();
        private double _frameCounter = 0;
        private long _frameRate = 0;
        //TimeSpan _lastRender = new TimeSpan();
        private Font _font;

        protected bool _renderUpdate = false;

        private bool _disposed = false; 
        #endregion

        // destructor to finalize the object
        ~DirectXChart()
        {
            Dispose(false);
        }

        /// <summary>
        /// Release unmanaged resources. 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this._disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    if (_font != null)
                    {
                        _font.Dispose();
                        _font = null;
                    }

                    ReleaseResources();
                }

            }
            _disposed = true;
        }

        protected virtual void ReleaseResources() { }

		private void OnDirectXRender(object sender, EventArgs e)
		{
			OnDirectXRender();

            //if (ShowFrameRate)
            //{
            //    _frameCounter++;
            //    _frameRate = (long)(_frameCounter / this._stopwatch.Elapsed.TotalSeconds);
            //    _font.DrawString(null, _frameRate.ToString(), 25, 25, Colors.Red.ToArgb());
            //}
                
		}

		protected virtual void OnDirectXRender() { }

        protected virtual void ResetResources() { }

		#region IPlotterElement Members

        protected override void OnPlotterAttached(Plotter plotter)
        {
            this.plotter = (Plotter2D)plotter;

            if (plotter.GetType() == typeof(InjectedPlotter))
            {
                // we need to the the main DXHost
                //_dxHost = (plotter as InjectedPlotter).Plotter.Children.OfType<DirectXHost>().FirstOrDefault();
                _slimDXControl = (plotter as InjectedPlotter).Plotter.Children.OfType<SlimDXControl>().FirstOrDefault();
            }
            else
            {
                //_dxHost = plotter.Children.OfType<DirectXHost>().FirstOrDefault();
                _slimDXControl = plotter.Children.OfType<SlimDXControl>().FirstOrDefault();
            }

            //if (_dxHost == null)
            //    throw new InvalidOperationException("First add DirectXHost to plotter.Children");

            //_dxHost.AddDXChild(this);
            //_dxHost.Render += OnDirectXRender;

            _slimDXControl.AddDXChild(this);
            //_slimDXControl.MainLoop += OnDirectXRender;
            _slimDXControl.SetRenderEngine(this);

            if (!_stopwatch.IsRunning)
                _stopwatch.Start();

#if DEBUG
            ShowFrameRate = true;
#else
            ShowFrameRate = false;
#endif
        }

        protected override void OnPlotterDetaching(Plotter plotter)
        {
            //_dxHost.RemoveChild(this);
            //_dxHost.Render -= OnDirectXRender;

            _slimDXControl.RemoveChild(this);
            //_slimDXControl.MainLoop -= OnDirectXRender;

            this.plotter = null;
        }

		#endregion

        protected override void OnRenderCore(DrawingContext dc, RenderState state)
        {
            OnDirectXRender();
        }

        #region IRenderEngine Members

        public void OnDeviceCreated(object sender, EventArgs e)
        {
            _font = new Font(Device, 16, 0, SlimDX.Direct3D9.FontWeight.Bold, 0, false,
                        CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.DontCare, "Arial");

            //OnDeviceCreated(sender, e);
            ResetResources();
        }

        public void OnDeviceDestroyed(object sender, EventArgs e)
        {
            if (_font != null)
                _font.Dispose();
        }

        public void OnDeviceLost(object sender, EventArgs e)
        {
            if (_font != null)
                _font.Dispose();
        }

        public void OnDeviceReset(object sender, EventArgs e)
        {
            SlimDXControl control = sender as SlimDXControl;
            if (control == null)
                throw new ArgumentNullException("sender");

            if (_font != null)
                _font.Dispose();

            _font = new Font(Device, 16, 0, SlimDX.Direct3D9.FontWeight.Bold, 0, false,
                        CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.DontCare, "Arial");
        }

        public void OnMainLoop(object sender, EventArgs e)
        {
            // only process our rendering if the data is updated
            //if (_renderUpdate)
            //{
            //    OnDirectXRender();
            //}
            OnDirectXRender();

            if (ShowFrameRate)
            {
                _frameCounter++;
                _frameRate = (long)(_frameCounter / this._stopwatch.Elapsed.TotalSeconds);

                if(_font != null)
                    _font.DrawString(null, _frameRate.ToString(), 50, 50, Colors.Red.ToArgb());
            }

        }

        public void OnRenderStarted(object sender, EventArgs e)
        {
            //if (!_stopwatch.IsRunning)
            //{
            //    _stopwatch.Start();
            //    ShowFrameRate = true;
            //}
        }

        public void OnRenderStopped(object sender, EventArgs e)
        {
            //if (_stopwatch.IsRunning)
            //    _stopwatch.Stop();
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
